﻿using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Red.Core;
using Red.EngineData.Protocol.Interop;

namespace Red.Controls.ViewModels
{
    #region Converters

    /// <summary>
    /// Create proper icon based on entry type
    /// </summary>
    public sealed class InteropDebugEntryTypeToCanvasConverter : IValueConverter
    {
        public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
        {
            InteropDebugEntryType entry = (InteropDebugEntryType)value;

            switch ( entry )
            {
                case InteropDebugEntryType.Error:
                    return Application.Current.TryFindResource( "appbar_close" ) as Canvas;
                case InteropDebugEntryType.Warning:
                    return Application.Current.TryFindResource( "appbar_warning" ) as Canvas;
                case InteropDebugEntryType.DebugMessage:
                    return Application.Current.TryFindResource( "appbar_information_circle" ) as Canvas;
            }
            return null;
        }

        public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
        {
            return InteropDebugEntryType.Error;
        }
    }

    /// <summary>
    /// Shortens file path to file name with extension
    /// </summary>
    public sealed class InteropDebugEntryFileConverter : IValueConverter
    {
        public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
        {
            string filePath = (string)value;
            return Path.GetFileName( filePath );
        }

        public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
        {
            string filePath = (string)value;
            return Path.GetFileName( filePath );
        }
    }

    #endregion

    /// <summary>
    /// View model for interop debug console
    /// </summary>
    public sealed class InteropDebugConsoleViewModel : ViewModel
    {
        #region Properties

        /// <summary>
        /// Filters entries with error type
        /// </summary>
        public bool ErrorsFilterEnabled { get; set; }

        /// <summary>
        /// Filters entries with warning type
        /// </summary>
        public bool WarningsFilterEnabled { get; set; }

        /// <summary>
        /// Filters entries with debug message type
        /// </summary>
        public bool MessagesFilterEnabled { get; set; }

        /// <summary>
        /// Number of entries with error type
        /// </summary>
        public int ErrorCount { get; set; }

        /// <summary>
        /// Number of entries with warning type
        /// </summary>
        public int WarningCount { get; set; }

        /// <summary>
        /// Number of entries with debug message type
        /// </summary>
        public int DebugMessageCount { get; set; }

        /// <summary>
        /// Container with owners filters
        /// </summary>
        public ObservableCollection<string> OwnersFilters { get; private set; }

        /// <summary>
        /// All interop debug entries
        /// </summary>
        public ObservableCollection<InteropDebugEntry> InteropDebugEntries { get; private set; }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor
        /// </summary>
        public InteropDebugConsoleViewModel()
        {
            ErrorsFilterEnabled = true;
            WarningsFilterEnabled = false;
            MessagesFilterEnabled = false;

            ErrorCount = 0;
            WarningCount = 0;
            DebugMessageCount = 0;

            OwnersFilters = new ObservableCollection<string>();
            OwnersFilters.Add( "All" );
            OwnersFilters.Add( "Unknown" );

            InteropDebugEntries = new ObservableCollection<InteropDebugEntry>();
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Callback method to add new interop debug entry
        /// </summary>
        /// <param name="newInteropDebugEntry">New debug entry object</param>
        public void OnNewInteropDebugEntry( InteropDebugEntry newInteropDebugEntry )
        {
            AddNewEntry( newInteropDebugEntry );
        }

        public void ClearLogs()
        {
            InteropDebugEntries.Clear();
            ErrorCount = WarningCount = DebugMessageCount = 0;

            OnPropertyChanged( "ErrorCount" );
            OnPropertyChanged( "WarningCount" );
            OnPropertyChanged( "DebugMessageCount" );
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Adds new interop debug entry to list
        /// </summary>
        /// <param name="newInteropDebugEntry">New interop debug entry</param>
        private void AddNewEntry( InteropDebugEntry newInteropDebugEntry )
        {
            string elementName = ExtractElementName( newInteropDebugEntry );
            newInteropDebugEntry.OwnerElement = elementName;

            switch ( newInteropDebugEntry.Type )
            {
                case InteropDebugEntryType.Error:
                    ErrorCount++;
                    OnPropertyChanged( "ErrorCount" );
                    break;
                case InteropDebugEntryType.Warning:
                    WarningCount++;
                    OnPropertyChanged( "WarningCount" );
                    break;
                case InteropDebugEntryType.DebugMessage:
                    DebugMessageCount++;
                    OnPropertyChanged( "DebugMessageCount" );
                    break;
            }

            newInteropDebugEntry.Order = InteropDebugEntries.Count;
            InteropDebugEntries.Add( newInteropDebugEntry );
        }

        /// <summary>
        /// Extracts element name from interop expression
        /// </summary>
        /// <param name="newInteropDebugEntry">New interop debug entry</param>
        /// <returns>Extracted element name</returns>
        private string ExtractElementName( InteropDebugEntry newInteropDebugEntry )
        {
            string exp = newInteropDebugEntry.Expression;

            var firstDotIndex = exp.IndexOf( "." );
            var leftBracketIndex = exp.IndexOf( "[" );
            var rightBracketIndex = exp.IndexOf( "]" );

            if ( leftBracketIndex != -1 && rightBracketIndex != -1 )
            {
                var categoryName = exp.Substring( firstDotIndex + 1, leftBracketIndex - ( firstDotIndex + 1 ) );
                var filterName = exp.Substring( leftBracketIndex + 1, rightBracketIndex - ( leftBracketIndex + 1 ) );
                var finalName = categoryName + " : " + filterName;
                if ( OwnersFilters.Contains( finalName ) == false )
                {
                    OwnersFilters.Add( finalName );
                }

                return finalName;
            }

            return "Unknown";
        }

        #endregion
    }
}
